{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Flow Run Management\n",
    "\n",
    "**Prerequisite** - To make the most of this tutorial, you'll need:\n",
    "- A local clone of the prompt flow repository\n",
    "- A Python environment with Jupyter Notebook support (such as Jupyter Lab or the Python extension for Visual Studio Code)\n",
    "- Know how to program with Python :)\n",
    "\n",
    "_A basic understanding of Machine Learning can be beneficial, but it's not mandatory._\n",
    "\n",
    "\n",
    "**Learning Objectives** - By the end of this tutorial, you should be able to:\n",
    "- manage runs via run.yaml\n",
    "- create run which references another runs inputs\n",
    "- create run with connection override\n",
    "\n",
    "\n",
    "**Motivations** - This guide will walk you through local run management abilities."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 0. Install dependent packages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install -r ../../requirements.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Create necessary connections\n",
    "Connection helps securely store and manage secret keys or other sensitive credentials required for interacting with LLM and other external tools for example Azure Content Safety.\n",
    "\n",
    "This notebook's will use connection `open_ai_connection` inside, we need to set up the connection if we haven't added it before. After created, it's stored in local db and can be used in any flow.\n",
    "\n",
    "Prepare your Azure Open AI resource follow this [instruction](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal) and get your `api_key` if you don't have one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "from promptflow.client import PFClient\n",
    "from promptflow.connections import AzureOpenAIConnection, OpenAIConnection\n",
    "\n",
    "# client can help manage your runs and connections.\n",
    "pf = PFClient()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    conn_name = \"open_ai_connection\"\n",
    "    conn = pf.connections.get(name=conn_name)\n",
    "    print(\"using existing connection\")\n",
    "except:\n",
    "    # Follow https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource?pivots=web-portal to create an Azure Open AI resource.\n",
    "    connection = AzureOpenAIConnection(\n",
    "        name=conn_name,\n",
    "        api_key=\"<test_key>\",\n",
    "        api_base=\"<test_base>\",\n",
    "        api_type=\"azure\",\n",
    "        api_version=\"<test_version>\",\n",
    "    )\n",
    "\n",
    "    # use this if you have an existing OpenAI account\n",
    "    # connection = OpenAIConnection(\n",
    "    #     name=conn_name,\n",
    "    #     api_key=\"<user-input>\",\n",
    "    # )\n",
    "\n",
    "    conn = pf.connections.create_or_update(connection)\n",
    "    print(\"successfully created connection\")\n",
    "\n",
    "print(conn)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Create run with YAML file\n",
    "\n",
    "You can save configurations for a run in a YAML file to save the effort to repeately provide them in SDK/CLI.\n",
    "In this step, we will create a sample run with a YAML file. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from promptflow.client import load_run\n",
    "\n",
    "# load a run from YAML file\n",
    "base_run = load_run(\n",
    "    source=\"../../flows/standard/web-classification/run.yml\",\n",
    "    # override the default params in the YAML file\n",
    "    params_override=[{\"column_mapping\": {\"url\": \"${data.url}\"}}],\n",
    ")\n",
    "\n",
    "# create the run\n",
    "base_run = pf.runs.create_or_update(run=base_run)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "details = pf.get_details(base_run)\n",
    "details.head(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 Create a flow run which uses an existing run's inputs\n",
    "\n",
    "When running a flow with an existing run, you can reference either it's inputs or outputs in column mapping.\n",
    "The following code cell show how to reference a run's inputs in column mapping."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from promptflow.entities import Run\n",
    "\n",
    "# directly create the run object\n",
    "run = Run(\n",
    "    # local flow file\n",
    "    flow=\"../../flows/standard/web-classification\",\n",
    "    # run name\n",
    "    run=base_run,\n",
    "    column_mapping={\n",
    "        # reference another run's inputs data column\n",
    "        \"url\": \"${run.inputs.url}\",\n",
    "    },\n",
    ")\n",
    "\n",
    "base_run = pf.runs.create_or_update(\n",
    "    run=run,\n",
    ")\n",
    "\n",
    "pf.runs.stream(base_run)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Create a flow run with connection override\n",
    "\n",
    "Sometime you want to switch connection or deployment name inside a flow when submitting it.\n",
    "Connection override provided an easy way to do it without changing original `flow.dag.yaml`.\n",
    "In the following code cell, we will submit flow `web-classification` and override it's connection to `open_ai_connection`. \n",
    "Please make sure the connection `open_ai_connection` exists in your local environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "run = Run(\n",
    "    # local flow file\n",
    "    flow=\"../../flows/standard/web-classification\",\n",
    "    data=\"../../flows/standard/web-classification/data.jsonl\",\n",
    "    # override connection for node classify_with_llm & summarize_text_content\n",
    "    # you can replace connection to your local connections\n",
    "    connections={\n",
    "        \"classify_with_llm\": {\"connection\": \"open_ai_connection\"},\n",
    "        \"summarize_text_content\": {\"connection\": \"open_ai_connection\"},\n",
    "    },\n",
    ")\n",
    "\n",
    "base_run = pf.runs.create_or_update(\n",
    "    run=run,\n",
    ")\n",
    "\n",
    "pf.runs.stream(base_run)"
   ]
  }
 ],
 "metadata": {
  "description": "Flow run management",
  "kernelspec": {
   "display_name": "github_v2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  },
  "resources": "examples/requirements.txt, examples/flows/standard/web-classification"
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
